//: C15:Wind4.cpp
// Extensibility in OOP

#include <iostream>

using namespace std;

enum note {
    middleC,
    Csharp,
    Cflat
}; // Etc.

class Instrument {
public:
    virtual void play(note) const {
        cout << "Instrument::play" << endl;
    }
    virtual char *what() const {
        return "Instrument";
    }
    // Assumen this will modify the object:
    virtual void adjust(int) {}
};

class Wind : public Instrument {
public:
    void play(note) const {
        cout << "Wind::play" << endl;
    }
    char *what() const {
        return "Wind";
    }
    void adjust(int) {}
};

class Percussion : public Instrument {
public:
    void play(note) const {
        cout << "Percussion::play" << endl;
    }
    char *what() const {
        return "Percussion";
    }
    void adjust(int) {}
};

class Stringed : public Instrument {
public:
    void play(note) const {
        cout <<"Stringed::play" << endl;
    }
    char *what() const {
        return "Stringed";
    }
    void adjust(int) {}
};

class Brass : public Wind {
public:
    void play(note) const {
        cout << "Brass::play" << endl;
    }
    char *what() const {
        return "Brass";
    }
};

class Woodwind : public Wind {
public:
    void play(note) const {
        cout << "Woodwind::play" << endl;
    }
    char *what() const {
        return "Woodwind";
    }
};

// Identical function from before:
void tune(Instrument &i) {
    // ...
    i.play(middleC);
}

// New function:
void f(Instrument &i) {
    i.adjust(1);
}

// Upcasting during array initilaization:
Instrument *A[] = {
    new Wind,
    new Percussion,
    new Stringed,
    new Brass
};

int main() {
    Wind flute;
    Percussion drum;
    Stringed violin;
    Brass flugelhorn;
    Woodwind recorder;

    tune(drum);
    tune(flute);
    tune(violin);
    tune(flugelhorn);
    tune(recorder);
    f(flugelhorn);

    return 0;
} ///:~
